﻿#include "YAudioPlayer.h"
#include <QDebug>

class CYAudioPlayer : public YAudioPlayer
{
	//暂停
	void Pause(bool is_pause)
	{
		if (is_pause)
		{
			SDL_PauseAudio(1);//1代表停止播放
			pause_begin = NowMs();//记录暂停的时间
		}
		else
		{
			//去掉暂停的事件
			if (pause_begin > 0)
				last_ms_ += (NowMs() - pause_begin);//最后播放 的时间=当前时间-过去的时间
			SDL_PauseAudio(0);//0代表开始播放
		}

	}

	bool Open(YAudioSpec& audioSpec)
	{
		//退出上一次音频
		SDL_QuitSubSystem(SDL_INIT_AUDIO);

		SDL_AudioSpec sdl_spec;
		sdl_spec.freq = audioSpec.freq;
		sdl_spec.format = audioSpec.format;
		sdl_spec.channels = audioSpec.channels;
		sdl_spec.samples = audioSpec.samples;
		sdl_spec.silence = 0;
		sdl_spec.userdata = this;
		sdl_spec.callback = AudioCallback;
		//打开SDL音频播放
		if (SDL_OpenAudio(&sdl_spec, nullptr) < 0)
		{
			qDebug() << "SDL_OpenAudio->" << SDL_GetError() << endl;
			return false;
		}
		//开始播放
		SDL_PauseAudio(0);//0代表开始播放，1代表停止播放
		return true;
	}

	/// <summary>
	/// 关闭SDL音频播放器
	/// </summary>
	void Close()
	{
		SDL_QuitSubSystem(SDL_INIT_AUDIO);
		std::unique_lock<std::mutex> lock(mux_);
		audio_datas_.clear();
		cur_pts_ = 0; //当前播放位置
		last_ms_ = 0;  //上次的时间戳
		pause_begin = 0;//暂停开始时间戳
	}

	/// <summary>
	/// SDL音频播放回调函数
	/// </summary>
	/// <param name="stream">指向 SDL 音频输出缓冲区的指针，需要填充音频数据</param>
	/// <param name="len">输出缓冲区的大小（字节数）</param>
	void Callback(unsigned char* stream, int len)
	{
		//初始化输出缓冲区，将其全部置零（静音状态）,同时也会把残余旧数据清零，确保数据都是最新的
		SDL_memset(stream, 0, len);
		//互斥锁，确保只有一个线程能够访问
		std::unique_lock<std::mutex> lock(mux_);
		if (audio_datas_.empty())return;
		auto buf = audio_datas_.front();
		// 1 buf 大于stream缓冲  offset记录位置
		// 2 buf 小于stream 缓冲  拼接
		int mixed_size = 0;     //已经处理的字节数
		int need_size = len;    //还需要处理的字节数

		cur_pts_ = buf.pts;     //当前播放的pts
		last_ms_ = NowMs();     //计时开始播放

		while (mixed_size < len)
		{
			if (audio_datas_.empty())break;
			buf = audio_datas_.front();
			//计算当前缓冲区剩余未处理的数据大小
			int size = buf.data.size() - buf.offset;

			//若剩余数据超过需要的量，截取需要的部分
			if (size > need_size)
			{
				size = need_size;
			}
			//使用SDL库将当前缓冲区数据混合到输出流中
			SDL_MixAudio(stream + mixed_size,
				buf.data.data() + buf.offset,
				size, SDL_MIX_MAXVOLUME);
			//更新计数：减少需要的数据量，增加已处理的数据量
			need_size -= size;
			mixed_size += size;
			//标记已处理数据的位置
			buf.offset += size;
			//若当前缓冲区（list<YAudioData>）已全部处理完，从队列中移除
			if (buf.offset >= buf.data.size())
			{
				audio_datas_.pop_front();
			}
		}
	}

	long long cur_pts()
	{
		double ms = 0;
		if (last_ms_ > 0)
			ms = NowMs() - last_ms_;//距离上次写入缓冲的播放时间毫秒
		//pts 毫秒换算pts的时间基数
		if (time_base_ > 0)
			ms = ms / (double)1000 / (double)time_base_;
		return cur_pts_ + ms;
	}

private:
	long long cur_pts_ = 0; //当前播放位置
	long long last_ms_ = 0;  //上次的时间戳
	long long pause_begin = 0;//暂停开始时间戳
};

YAudioPlayer* YAudioPlayer::Create()
{
	static CYAudioPlayer cyp;
	return &cyp;
}

void YAudioPlayer::Push(AVFrame* frame)
{
	if (!frame || !frame->data[0])return;
	std::vector<unsigned char> buf;
	int sample_size = 4;
	int channels = frame->channels;
	unsigned char* L = frame->data[0];
	unsigned char* R = frame->data[1];
	unsigned char* data = nullptr;
	if (channels == 1)
	{
		Push(frame->data[0], frame->nb_samples * sample_size, frame->pts);
		return;
	}
	//暂时支持双通道
	switch (frame->format)
	{
		//case AV_SAMPLE_FMT_S16P:        ///< signed 16 bits, planar
	case AV_SAMPLE_FMT_S32P:        ///< signed 32 bits, planar
	case AV_SAMPLE_FMT_FLTP:        ///< float, planar
		buf.resize(frame->linesize[0]);
		data = buf.data();
		// LLLL RRRR  32
		// LR LR LR LR 4
		for (int i = 0; i < frame->nb_samples; i++)
		{
			memcpy(data + i * sample_size * channels,
				L + i * sample_size, sample_size);
			memcpy(data + i * sample_size * channels + sample_size,
				R + i * sample_size, sample_size);
		}
		Push(data, frame->linesize[0], frame->pts);
		return;
		break;
	default:
		break;
	}
	Push(frame->data[0], frame->linesize[0], frame->pts);
}
bool YAudioPlayer::Open(YAVParameters& para)
{
	if (para.time_base->num > 0)
		time_base_ = (double)para.time_base->den / (double)para.time_base->num;
	return Open(para.para);
}
bool YAudioPlayer::Open(AVCodecParameters* para)
{
	YAudioSpec spec;
	spec.channels = para->channels;
	spec.freq = para->sample_rate;

	AVSampleFormat;
	switch (para->format)
	{
	case AV_SAMPLE_FMT_S16:         ///< signed 16 bits
	case AV_SAMPLE_FMT_S16P:        ///< signed 16 bits, planar
		spec.format = AUDIO_S16;
		break;
	case AV_SAMPLE_FMT_S32:         ///< signed 32 bits
	case AV_SAMPLE_FMT_S32P:        ///< signed 32 bits, planar
		spec.format = AUDIO_S32;
		break;
	case AV_SAMPLE_FMT_FLT:         ///< float
	case AV_SAMPLE_FMT_FLTP:        ///< float, planar
		spec.format = AUDIO_F32;
		break;
	default:
		break;
	}
	return Open(spec);
}

YAudioPlayer::YAudioPlayer()
{
}

YAudioPlayer::~YAudioPlayer()
{
	//初始化SDL音频
	SDL_Init(SDL_INIT_AUDIO);
}
